#!/usr/bin/env python
# coding: utf-8

# #订单编号：共28010条
# #总金额：该笔订单的总金额
# #买家实际支付金额：实际成交金额。分为已付款和未付款两种情况：
# #已付款：买家实际支付金额 = 总金额 - 退款金额
# #未付款：买家实际支付金额 = 0
# #收货地址：维度为省份,共包含31个省市
# #订单创建时间：2020年2月1日 至 2020年2月29日
# #订单付款时间：2020年2月1日 至 2020年3月1日
# #退款金额：付款后申请退款的金额。没有申请退款或没有付过款，退款金额为0

# In[47]:


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly as py
import plotly.graph_objs as go
import datetime
from plotly.offline import download_plotlyjs, init_notebook_mode
from pyecharts.charts import Map
from pyecharts import options as opts
from pyecharts.charts import Funnel, Page
pyplot = py.offline.iplot

#进行绘图时，可以直接生成图像，省下plt.show()
get_ipython().run_line_magic('matplotlib', 'inline')
plt.rcParams['font.sans-serif']=['SimHei'] # 用黑体显示中文
sns.set(font='SimHei', font_scale=0.8)      # 解决Seaborn中文显示问题


# In[48]:


data = pd.read_csv('tmall_order_report.csv')
data.head()


# # 数据预处理

# In[49]:


data.info()


# 可以看出订单付款时间这个字段有空值，订单创建时间和付款时间都为object类型，需要转成datetime类型

# In[50]:


data.columns
#收货地址和订单付款时间后面存在空格,删除空格
data.rename(columns={'收货地址 ': '收货地址', '订单付款时间 ':'订单付款时间'},inplace = True)
data.columns


# In[51]:


#将时间字段改为日期格式
data['订单创建时间'] = pd.to_datetime(data['订单创建时间'])
data['订单付款时间'] = pd.to_datetime(data['订单付款时间'])


# In[52]:


data.info()


# In[53]:


#以某年某月的形式创建新字段
data['创建时间'] = data['订单创建时间'].dt.strftime('%m-%d')
data['付款时间'] = data['订单付款时间'].dt.strftime('%m-%d')


# In[54]:


def wd(x):
    if x == 0:
        result = '星期一'
    elif x == 1:
        result = '星期二'
    elif x == 2:
        result = '星期三'
    elif x == 3:
        result = '星期四'
    elif x == 4:
        result = '星期五'
    elif x == 5:
        result = '星期六'
    else:
        result = '星期日'
    return result
    

data['创建星期'] = data['订单创建时间'].dt.weekday.apply(wd)
data['付款星期'] = data['订单付款时间'].dt.weekday.apply(wd)
data['创建时刻'] = data['订单创建时间'].dt.hour
data['付款时刻'] = data['订单付款时间'].dt.hour

data.head()


# In[55]:


data['收货地址'].unique() #去重后的值


# In[56]:


#将地址名称进行简化
data['收货地址'] = data['收货地址'].str.replace('省','').str.replace('自治区','').str.replace('壮族','').str.replace('维吾尔','').str.replace('回族','')
data['收货地址'].unique()


# In[57]:


sum(data['订单付款时间'].isnull())
#订单付款时间这个字段的缺失值有三千多个,现实中下单但未付款的记录是存在的，缺失量也不是很大，不需要进行处理


# In[58]:


data[data['订单付款时间'].isnull() & data['买家实际支付金额']>0].size
#不存在没有付款但却有支付记录的异常值


# In[59]:


data.describe()
#可以看出总金额的最大值为188320，而买家实际支付金额的最大值为16065，说明买家并没有付款。总金额的最大值与75%的值相距非常大，可能是异常值


# In[60]:


plt.boxplot(data['总金额'])


# 可以看出，由于总金额高于175000的数据离上极限非常远，并且从25000-175000这段都是空白的，因此这个点为异常值

# In[61]:


#删除异常值
data.drop(data[data['总金额']>175000].index,inplace=True)


# In[62]:


#any表示只要有一个True就返回True
data.duplicated().any()
#没有重复值


# # 数据分析与可视化

# ## 描述性统计

# In[63]:


#将买家实际支付金额和退款金额为0的值转换成空值
data_desc = data.copy()
data_desc['买家实际支付金额'] = np.where(data_desc['订单付款时间'].isnull(),np.nan,data_desc['买家实际支付金额'])
data_desc['退款金额'] = data_desc['退款金额'].replace(0,np.nan)
data_desc.describe()


# #订单总数为28009条，买家支付的订单数为24087条，退款订单有5646条
# #订单总金额的最大值为16065，最小值为1，平均值为100.23
# #实际支付订单平均每单79.0，金额最小0，金额最大16065
# #退款订单平均每单退款101.4，金额最小1，金额最大3800。

# ## 销售分析

# In[64]:


#月销售分析
plt.figure(figsize=(16,12))
plt.subplot(2,2,1)
(data.groupby('付款时间')['买家实际支付金额'] .sum()).plot(marker='o')
plt.ylabel('销售额',fontsize=12)

plt.subplot(2,2,2)
(data.groupby('付款时间')['买家实际支付金额'].count()).plot(color='g',marker='^')
plt.ylabel('销售量',fontsize=12)

plt.subplot(2,2,3)
(data.groupby('付款时间')['买家实际支付金额'].mean()).plot(color='m',marker='>')
plt.ylabel('日均销售额',fontsize=12)


# ##可以看出，2月16日以前销售额很少，仅在2月4日和2月9日达到两个小高峰，2月10-2月16日销售额一直很低，2月17日销售量和销售额开始持续上升，一直到2月25日达到本月最高销售额，之后持续下降，在3月1日降到最低。日均销售额最低在2月6日，平均每笔订单消费不超过20元。
# ##### 问题分析：
# ##2月初销量低可能是因为春节假期，查阅可知，2020年的春节假期为1月24日至2月2日，但是当时正是疫情开始，复工复产时间推迟至不早于2月9日24时，2月10日-2月16日正好是销售最低迷的时间，应该是因为消费者正开始复工复产，无暇消费。
# ##3月1日销售额突降是因为该日订单只记录了在2月29日创建但在3月1日支付的，并不是3月1日的所有交易数据，在这里我们可以忽略3月1日。
# 

# In[65]:


#周销售分析和日销售分析
week_order = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
data_week_mean = [data.groupby('付款星期').sum()['买家实际支付金额'].loc[i] for i in week_order]
data_week_count = [data.groupby('付款星期').count()['订单编号'].loc[i] for i in week_order]
data_hour_mean = data.groupby('付款时刻')['买家实际支付金额'].sum()
data_hour_count = data.groupby('付款时刻')['买家实际支付金额'].count()

plt.figure(figsize=(16,12))
plt.subplot(2,2,1)
plt.bar(week_order,data_week_mean,color='g',alpha=0.7,edgecolor='black')
plt.ylabel('销售额',fontsize=12)

plt.subplot(2,2,2)
plt.bar(week_order,data_week_count,color='red',alpha=0.7,edgecolor='black')
plt.ylabel('销售量',fontsize=12)

plt.subplot(2,2,3)
plt.plot(data_hour_mean,color='orange',marker='*')
plt.ylabel('销售额',fontsize=12)

plt.subplot(2,2,4)
plt.plot(data_hour_count,color='firebrick',marker='*')
plt.ylabel('销售量',fontsize=12)


# ##### 可以看出，
# ##每周销售最好的时候是周五，其次是周二，最差的是周一。周末并不是预想中销售最好的时间，甚至比大部分工作日差，推测是因为周五过后就是假期，愉快的心情促进人们消费。
# ##从凌晨12点开始到凌晨5点的销售量逐渐降低，5点时销售达到最低点，然后开始上升，在早上10点、15点，21点分别有峰值，21点销量最高，到了晚上22点销量逐渐下降
# ##### 建议：
# ##在周五可以开办优惠活动促进消费者消费，例如满减或打折优惠
# ##促销信息、产品推广广告的推送时间最好安排在晚上9点，此时消费人数最多，信息的曝光量最大，能带来最大收益；

# ## 产品价格分析

# 因为数据集中即没有包含产品名称，也没有包含产品价格，因此我们将订单总金额当成产品的价格，分析什么价格的产品更受消费者欢迎。

# In[66]:


(data['总金额']).plot.hist(bins=50)
#可以看出产品价格都在2000以下，大部分产品价格都在500以下，价格差距过大导致刻度较大，因此剔出过大的数据重新作图


# In[67]:


(data[data['总金额']<500]['总金额']).count()
#有27825条消费订单在500元以下，因此筛选出总金额500以内的数据进行绘图


# In[68]:


plt.figure(figsize=(8,6))
(data[data['总金额']<500]['总金额']).plot.hist(bins=50,facecolor='deeppink')
plt.xlabel('总金额',fontsize=12)


# 20-120元的订单较多，大部分订单的价格都在200以下

# In[69]:


#根据价格对订单进行分组
#指定多个区间
bins = [0, 20, 40, 60, 80, 100, 125, 150, 175, 200, 250, 300, 500, 16065]
price_label = ['0-20', '20-40', '40-60', '60-80', '80-100', '100-125','125-150','150-175',
               '175-200', '200-250', '250-300', '300-500', '500以上']
price_cut = [pd.cut(data['总金额'],bins = bins,labels=price_label).value_counts()[i] for i in price_label]

plt.figure(figsize=(10,8))
sns.barplot(x=price_label,y=price_cut,palette='Blues_r')
plt.xlabel('订单金额',fontsize=12)
plt.ylabel('订单数',fontsize=12)
# 在柱状图上显示具体数值, ha参数控制水平对齐方式, va控制垂直对齐方式
x =  [i for i in range(len(price_label))]
for i,j in zip(x, price_cut):
    plt.text(i, j+50, j,ha='center', va='center', fontsize=12, rotation=0,color='b')


# ##### 可以看出：
# ##订单数最高的在20-40这个区间，最低的在0-20这个区间
# ##大部分订单金额都在250元以下，20元以上，说明消费者更喜欢20-250这个价格区间的产品
# ##### 建议：
# ##可以对20-40价格区间的商品进行大力推广和广告宣传，对于20-250这个价格区间的产品偶尔开展一些优惠活动来吸引顾客
# 

# ## 地区分析

# In[70]:


data_area = data.groupby('收货地址')['买家实际支付金额'].sum().sort_values(ascending=False).reset_index()
plt.figure(figsize=(15,10))
#sns.palplot(sns.color_palette('Oranges'))
sns.barplot(x='收货地址',y='买家实际支付金额',data=data_area,palette='OrRd_r')
plt.title('不同地区的销售情况',fontsize=20)


# In[71]:


data_area_list = [list(i) for i in zip(data_area['收货地址'], np.round(data_area['买家实际支付金额']))]
map = Map()
map.add("销售额", data_area_list, maptype='china', is_map_symbol_show=True)
map.set_global_opts(title_opts=opts.TitleOpts(title='各省市销售额'), 
                    visualmap_opts=opts.VisualMapOpts(min_=10, max_=200000 ,range_color=['#D7E3EF', '#163A69']))
                    
map.render_notebook()


# #### 可以看出：
# ##销售额最高的是上海，最低的西藏
# ##销售额较高的地区主要是在东部和南部沿海，四川省
# ##销售额较低的主要是在西部地区，例如西藏、青海、湖北等
# #### 建议：
# ##应该是因为西部等偏远地区不包邮且交通不是很便利，所以销售额较低。我们知道销售量最高的价格区间在20-40，这对于不包邮的地区购买是不划算的。但是从卖家成本看，提高这些地区的销售额比较困难。因此可以对西南、中部以及东北地区提高销售，开展优惠活动，同时要保持销售额较高的省份订单量

# # 转化率分析

# ### 1.整体转换率分析

# In[72]:


#用户行为路径为：创建订单 -> 订单付款 -> 订单成交 -> 订单全额成交
#计算各个阶段的订单数
data_create = data.shape[0] #创建的订单总数
data_pay = data[data['付款时间'].notnull()].shape[0]  #付款的订单数
data_pay_part = data[data['买家实际支付金额'] > 0].shape[0]  #实际订单成交量
data_pay_all = data[data['总金额'] == data['买家实际支付金额']].shape[0]  #全额成交的订单量


# In[73]:


#各个阶段的转换率
data_funnel = pd.DataFrame()
data_funnel['阶段'] = ['创建订单','支付订单','成交订单','全额成交订单']
data_funnel['订单量'] = [data_create,data_pay,data_pay_part,data_pay_all]
data_funnel['转换率%'] = np.round(data_funnel['订单量']/data_funnel['订单量'][0],4)*100
data_funnel['支付订单的转换率%'] = np.round(data_funnel['订单量']/data_funnel['订单量'][1],4)*100
data_funnel['支付订单的转换率%'][0]=np.nan
data_funnel


# In[74]:


#绘制漏斗图
#page = Page()
funnel1 = Funnel()
funnel1.add(series_name='转化率',
            data_pair=[list(z) for z in zip(data_funnel['阶段'] ,data_funnel['转换率%'])],
            label_opts=opts.LabelOpts(position='inside',formatter='{b}：{c}%'))
funnel1.set_colors(colors=['#B0CDDD', '#5C96BB', '#3470A3', '#163A69'])
funnel1.set_global_opts(title_opts=opts.TitleOpts(title='转化率'))
funnel1.render_notebook()
            


# ## 可以看出：
# ##最终全额成交订单占订单数的65.84%，成交订单占67.67%，说明有些顾客退款了已经付款的部分订单，推测可能是为了凑单或是商品质量不满意等其他原因。
# ##创建订单到支付订单的转化率有86%，说明有14%的用户在创建了订单以后，没有选择支付，而是取消了该笔订单的支付。应当重点追溯一下导致这个情况的原因是什么。可以查询创建订单以后的用户行为都有哪些，创建了订单以后，用户是立即取消了订单支付？还是用户离开了支付界面进行了其他行为？用户离开支付界面，都进行了哪些行为，是继续浏览同类商品？还是退出app忘记支付？是因为看到了其他同类更好的商品决定不购买该商品了？还是只是点错了，不小心进到了支付界面？还是想要购买的商品规格不符合自己的预期？提升创建订单到支付订单的转化率是较为关键的。
# ##支付订单到成交订单的转化率同样比较低，转换率下降了18%左右，说明退款率较高
# ## 建议：
# ##退款率较高说明商品存在让顾客不满意的地方，应该找出原因降低退款率，可以从商品质量、商品包装、图片是否与图片相符、物流等方面改善，从而提高销售量。

# ### 2.各省转换率分析

# In[75]:


data_province_create = data.groupby('收货地址')['总金额'].count().reset_index()  #各地区订单量
data_province_pay = data.groupby('收货地址')['付款时间'].count().reset_index()   #支付的订单数
data_province_tran = pd.merge(data_province_create,data_province_pay,on='收货地址',how='left')  #两张表左连接
data_province_tran.rename(columns = {'总金额':'创建订单量','付款时间':'支付订单量'},inplace = True)  #改列名
data_province_tran['转换率'] = round(data_province_tran['支付订单量']/data_province_tran['创建订单量'],2) #计算转换率
data_province_tran.head()


# In[76]:


plt.figure(figsize=(16,8))
plt.bar('收货地址','转换率',data=data_province_tran,color='b',edgecolor='black',alpha=0.6)
plt.title('各省的转换率',fontsize=20)


# #### 可以看出：
# ##大部分省份的转换率都是处于一个相对稳定的水平，都在0.84左右，部分地区例如上海‘宁夏、青海等地区高达90%以上，说明大部分地区的用户在支付界面取消订单的现象并不严重。
# ##西藏、新疆和湖北的转换率稍微较低，可能是因为物流不太方便，许多商家是不往这两个地区发货的，因此转换率较低。而湖北地区的转化率较低，很可能是因为受到疫情影响。2020年的2月份正是湖北疫情严重的时期，因此很多消费者会选择取消订单，导致转换率较低。

# # 总结

# ####成交金额方面，新年过后复工的一周左右，销售额会出现快速的增长，在月底前达到一个小高峰。因此可以在新年过后一周左右的时间，提前准备好库存，做好销售计划等。
# ####每周的周二和周五是销售额较高的时间段。如果有促销计划什么的，可以重点在周二和周五进行。
# ####每日的10点、15点、21-22点的时间段是销售额较高的时间段，如果有促销活动、优惠券发放、新品推荐等推送内容，可以选择在这些时间段进行发放，效果会更佳。
# ####产品价格方面，大多数消费者的消费区间在20-250，其中20-40这个价格区间的消费者最多，可以对20-40价格区间的商品进行大力推广和广告宣传，对于20-250这个价格区间的产品偶尔开展一些优惠活动来吸引顾客
# ####地区方面，江浙沪一带、以及北京、广东、四川等地区的成交金额是比较高的，而新疆西藏内蒙古等其他地区的成交金额普遍较低。可以根据以后的发展计划、策略、综合考虑物流、成本等因素进行产品销售的调整。
# ####退款金额和销售金额的趋势基本吻合。销售额高相应的退款行为发生次数也多。
# ####转换率方面，创建订单->支付订单->成交订单的转化率均较低，应当从各方面寻找原因，加强物流管理、提升产品质量、提高服务态度等等，从而提高各环节转换率，增加销量。
# ####对于转换率较低的省份，因受到疫情影响，因此转换率较低，出现大量退款等行为，一方面要全力配合防疫工作，另一方面要在疫情到来之前，提前做好应对措施，及时调整营销策略等。

# In[ ]:





# In[ ]:





# In[ ]:





# In[ ]:




